﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using SoftwareConsulting.BI11.Studio.InternalServices;
using SoftwareConsulting.BI11.Studio.Core.Project;
using SoftwareConsulting.BI11.Studio.Core.Project.Metadata;
using SoftwareConsulting.BI11.Studio.UI.ProjectExplorer.Extensions;
using SoftwareConsulting.BI11.Studio.UI.Properties;
using SoftwareConsulting.BI11.Controls.Metadata;

namespace SoftwareConsulting.BI11.Studio.UI.ProjectExplorer.Calculations
{        
    /// <summary>
    /// Класс формы запуска Расчета
    /// </summary>
    public partial class CalculationRunDialog : RestorableForm
    {
        private ProjectExplorerForm _projectExplorer;
        private ProjectDescriptor _projectLink;
        private ICalculation _calculation;
        private string _calculationResult;
        private Thread _calculationThread;
        private bool _endCalculation;
        private System.Windows.Forms.Timer _checkCalculationTimer;
        private Dictionary<string, ITimeSeries> _changedSeries;
        private bool _changedSeriesNew;
        private object _locker;

        /// <summary>
        /// Обрабатывает смену временного ряда
        /// </summary>
        /// <param name="series"></param>
        private void TimeseriesChanged(ITimeSeries series)
        {
            if (!_changedSeries.ContainsKey(series.Label))
            {
                _changedSeries.Add(series.Label, series);
                lock (_locker)
                {
                    _changedSeriesNew = true;
                }
            }
        }

        /// <summary>
        /// Расчитывает в отдельном потоке
        /// </summary>
        private void CalculateInStandaloneThread()
        {
            if (WorldsBox.SelectedIndex > 0)
            {
                _calculationResult = _calculation.Calculate(TimeseriesChanged, _projectLink.RepositoryLink.GetOrSetWorldKeyByName(WorldsBox.SelectedItem as string));
            }
            else
            {
                _calculationResult = _calculation.Calculate(TimeseriesChanged);
            }
            _endCalculation = true;
        }

        /// <summary>
        /// Запускает расчет
        /// </summary>
        private void StartCalculation()
        {
            if (_projectLink.CalculationState == CalculationStates.None)
            {
                _projectLink.CalculationState = CalculationStates.Run;
                RunButton.Enabled = false;
                CancelCRButton.Enabled = false;
                PauseButton.Enabled = true;
                StopButton.Enabled = true;                
                RunButton.Text = Resources.BI_PROJECTEXPLORER_CALCULATION_RUN_CONTINUE;
                //вычисления
                _changedSeries = new Dictionary<string, ITimeSeries>();
                _changedSeriesNew = false;
                _endCalculation = false;
                _checkCalculationTimer = new System.Windows.Forms.Timer();
                _checkCalculationTimer.Interval = 1000;
                _checkCalculationTimer.Enabled = true;
                _checkCalculationTimer.Tick += new EventHandler(_checkCalculationTimer_Tick);
                _checkCalculationTimer.Start();                
                _calculationThread = new Thread(CalculateInStandaloneThread);                
                _calculationThread.Start();
            }
            else
            {
                RunButton.Enabled = false;
                PauseButton.Enabled = true;
                _projectLink.CalculationState = CalculationStates.Run;                
            }
        }

        /// <summary>
        /// Проверяет закончено ли вычисление
        /// </summary>
        private void _checkCalculationTimer_Tick(object sender, EventArgs args)
        {
            if (_endCalculation)
            {
                _checkCalculationTimer.Stop();
                _calculationThread.Abort();                
                if (!string.IsNullOrEmpty(_calculationResult))
                {
                    GeneralMethods.ShowInformation(Resources.BI_PROJECTEXPLORER_CALCULATION_RUN_FAILED + _calculationResult);
                }
                else
                {
                    GeneralMethods.ShowInformation(Resources.BI_PROJECTEXPLORER_CALCULATION_RUN_OK);
                }
                //закончили!
                CancelCRButton.Enabled = true;
                PauseButton.Enabled = false;
                StopButton.Enabled = false;
                RunButton.Enabled = true;
                RunButton.Text = Resources.BI_PROJECTEXPLORER_CALCULATION_RUN_CALCULATE;
                CalculationTabs.SelectedTabPage = ResultsTab; //go to results
            }
            lock (_locker)
            {
                if (_changedSeriesNew)
                {
                    _changedSeriesNew = false;                    
                    foreach (ListViewItem item in ResultsBox.Items)
                    {
                        item.SubItems[2].Text = _changedSeries.ContainsKey(item.Text) ? Resources.BI_PROJECTEXPLORER_CALCULATION_RUN_USED : Resources.BI_PROJECTEXPLORER_CALCULATION_RUN_NOTUSED;
                    }
                }
            }
        }

        /// <summary>
        /// Инициализирует диалог
        /// </summary>
        private void Initialize()
        {
            _calculationResult = string.Empty;
            this.Icon = MetadataObjectKind.Calculation.GetIcon();
            this.SetObjectViewerCaption(this.Text, _calculation);            
            //загружает цепочку моделей
            int c = _calculation.GetModelsCount();
            for (int i = 0; i < c; i++)
            {
                IModel model = _calculation.GetModelByIndex(i);
                ListViewItem item = ChainBox.Items.Add(model.Label);
                item.SubItems.Add(model.Name);
                item.SubItems.Add((i + 1).ToString());
            }
            //загружает используемые временные ряды
            var usedSeries = _calculation.GetUsedTimeSeries();
            foreach (KeyValuePair<Guid, ITimeSeries> entry in usedSeries)
            {
                ITimeSeries series = entry.Value;
                ListViewItem item = ResultsBox.Items.Add(series.Label);
                item.SubItems.Add(series.Name);
                item.SubItems.Add(Resources.BI_PROJECTEXPLORER_CALCULATION_RUN_NOTUSED);
            }
            tipBox1.Closed = !_projectExplorer.SimpleMode;
            WorldsBox.SelectedIndex = 0;            
            IFactsDimension wdim = _projectLink.RepositoryLink.WorldsDimension;            
            c = wdim.Items.ItemsCount;            
            for (int i = 0; i < c; i++)
            {
                WorldsBox.Properties.Items.Add(wdim.Items.GetItemByPosition(i).Name);
            }
            _locker = new object();
        }

        /// <summary>
        /// Конструктор класса
        /// </summary>
        public CalculationRunDialog(ProjectExplorerForm projectExplorer, ICalculation calculation)
        {
            _projectExplorer = projectExplorer;
            _projectLink = projectExplorer.ProjectLink;
            _calculation = calculation;
            InitializeComponent();
        }

        private void CancelCRButton_Click(object sender, EventArgs e)
        {
            Close();
        }

        private void CalculationRunDialog_Load(object sender, EventArgs e)
        {
            Initialize();
        }

        private void RunButton_Click(object sender, EventArgs e)
        {
            StartCalculation();
        }

        private void PauseButton_Click(object sender, EventArgs e)
        {
            if ((_calculationThread != null) && (!_endCalculation))
            {
                _projectLink.CalculationState = CalculationStates.Pause;
                PauseButton.Enabled = false;
                RunButton.Enabled = true;                
            }
        }

        private void StopButton_Click(object sender, EventArgs e)
        {
            if ((_calculationThread != null) && (!_endCalculation))
            {
                _projectLink.CalculationState = CalculationStates.Stop;
            }
        }

        /// <summary>
        /// Selects all series
        /// </summary>
        private void SelectAll(bool toSelect)
        {
            foreach (ListViewItem item in ResultsBox.Items)
            {
                item.Selected = toSelect;
            }            
        }

        /// <summary>
        /// Выделяет все ряды
        /// </summary>
        private void SelectAll()
        {
            SelectAll(true);
        }

        /// <summary>
        /// Отображает содержимео выбранного ряда
        /// </summary>
        private void ViewSelectedSeries()
        {
            foreach (ListViewItem item in ResultsBox.SelectedItems)
            {
                //пока что будет отображать каждый ряд по-отдельности,
                //потом лучше будет, если сделаю отображение в одном окне
                _projectExplorer.ShowTimeSeries(_projectLink.RepositoryLink.GetObjectDescriptorByLabel(item.Text, MetadataObjectKind.TimeSeries) as ITimeSeries);
            }
        }

        private void SelectAllButton_Click(object sender, EventArgs e)
        {
            
        }

        private void selectAllToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (!SelectAllButton.Checked)
            {
                SelectAllButton.Checked = true;
            }
            else
                SelectAll();
        }

        private void viewSelectedSeriesToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ViewSelectedSeries();
        }

        private void ViewTimeseriesButton_Click(object sender, EventArgs e)
        {
            ViewSelectedSeries();
        }

        private void tipBox1_OnRolledDown()
        {
            tipBox1.Top = 80;
            _projectExplorer.SimpleMode = true;
        }

        private void tipBox1_OnRolledUp()
        {
            tipBox1.Top = 150;
            _projectExplorer.SimpleMode = false;
        }

        private void SelectAllButton_CheckedChanged(object sender, EventArgs e)
        {
            SelectAll(SelectAllButton.Checked);
        }
    }
}
